package com.example.myproject.java8.stream;

import com.alibaba.rocketmq.shade.com.alibaba.fastjson.JSON;
import com.example.myproject.util.JsonUtil;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Created by Administrator on 2017/9/8.
 *
 * map 中间操作
 *一个流式处理可以分为三个部分：转换成流、中间操作、终端操作。如下图：
 * 中间操作：
 *filter,distinct,limit,skip,sorted,map,flatmap
 *
 * 2.2 映射
 在SQL中，借助SELECT关键字后面添加需要的字段名称，可以仅输出我们需要的字段数据，而流式处理的映射操作也是实现这一目的，在java8的流式处理中，主要包含两类映射操作：map和flatMap。
 * distinct基于Object.equals(Object)实现
 * 终端操作：
 * allMath,anyMatch,noneMatch,findFirst,findAny,count,reduce,Collect
 */
public class Demo {
    // 初始化
    static List<Student> students = new ArrayList<Student>() {
        {
            add(new Student(20160001, "孔明", 20, 1, "土木工程1", "武汉大学"));
            add(new Student(20160002, "孔明", 21, 2, "土木工程2", "武汉大学"));
            add(new Student(20160003, "孔明", 22, 3, "土木工程23", "武汉大学"));
            add(new Student(20160004, "云长", 21, 2, "信息安全", "武汉大学"));
            add(new Student(20161001, "翼德", 21, 2, "机械与自动化", "华中科技大学"));
            add(new Student(20161002, "元直", 23, 4, "土木工程", "华中科技大学"));
            add(new Student(20161003, "奉孝", 23, 4, "计算机科学", "华中科技大学"));
            add(new Student(20162001, "仲谋", 22, 3, "土木工程", "浙江大学"));
            add(new Student(20162002, "鲁肃", 23, 4, "计算机科学", "浙江大学"));
            add(new Student(20163001, "丁奉", 24, 5, "土木工程", "南京大学"));
        }
    };

    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        listToMap();
        // testFlatMap();
    }

    //只过滤武汉大学的集合
    public static void testFilter() {
        List<Student> whuStudents = students.stream()
                .filter(student -> "武汉大学".equals(student.getSchool()))
                .collect(Collectors.toList());
        System.out.println(whuStudents);
    }

    //去掉名字重复的，需要重些equal和hashcode
    //hashcode相同，equal可以不同，equal相同，hashcode一定相同
    public static void testDistinct() {
        List<Student> whuStudents = students.stream()
                .filter(student -> "武汉大学".equals(student.getSchool()))
                .distinct()
                .collect(Collectors.toList());
        System.out.println(whuStudents);
    }

    //limit
    //limit操作也类似于SQL语句中的LIMIT关键字，不过相对功能较弱，limit返回包含前n个元素的流，当集合大小小于n时，则返回实际长度，比如下面的例子返回前两个专业为土木工程专业的学生：

    public static void testLimit() {
        List<Student> whuStudents = students.stream()
                .filter(student -> "土木工程".equals(student.getMajor())).limit(2)
                .collect(Collectors.toList());
        System.out.println(whuStudents);
    }

    //sorted

    /**
     * 说到limit，不得不提及一下另外一个流操作：sorted。该操作用于对流中元素进行排序，sorted要求待比较的元素必须实现Comparable接口，如果没有实现也不要紧，我们可以将比较器作为参数传递给sorted(Comparator<? super T> comparator)，比如我们希望筛选出专业为土木工程的学生，并按年龄从小到大排序，筛选出年龄最小的两个学生，那么可以实现为：
     * 复杂的计算就采用这种方式
     */
    public static void testSorted() {
        List<Student> sortedCivilStudents = students.stream()
                .filter(student -> "土木工程".equals(student.getMajor())).sorted((s1, s2) -> s1.getAge() - s2.getAge())
                .limit(2)
                .collect(Collectors.toList());
        System.out.println(sortedCivilStudents);
    }

    /**
     * skip操作与limit操作相反，如同其字面意思一样，是跳过前n个元素，比如我们希望找出排序在2之后的土木工程专业的学生，那么可以实现为：
     * 通过skip，就会跳过前面两个元素，返回由后面所有元素构造的流，如果n大于满足条件的集合的长度，则会返回一个空的集合
     */
    public static void testSkip() {
        List<Student> civilStudents = students.stream()
                .filter(student -> "土木工程".equals(student.getMajor()))
                .skip(2)
                .collect(Collectors.toList());

        System.out.println(civilStudents);
    }

    //:: 代表方法名称
    public static void testMapFunction() {
        List<String> names = students.stream()
                .filter(student -> "计算机科学".equals(student.getMajor()))
                .map(Student::getName).collect(Collectors.toList());
        System.out.println(names);

        Map<String, String> tempmap = null;

        String g = null;
        if (g != null) {
            tempmap = new HashMap<>();
        }

        //错误场景1
        //labmba表达式定义的变量，必须在外面赋值一次， Map<String,String> tempmap = new Hashampa,不能赋值两次
//        List<String> names2 = students.stream()
//                .map(item -> {
//                    String temp = item.getSchool();
//                    temp = tempmap.get("sd");
//                    return temp;
//                }).collect(Collectors.toList());
//

    }


    public static void testFlatMap() {
        String[] strs = {"java8", "is", "easy", "to", "use"};
        List<String[]> distinctStrs = Arrays.stream(strs)
                .map(str -> str.split(""))  // 映射成为Stream<String[]>
                .distinct()
                .collect(Collectors.toList());
        for (String[] s1 : distinctStrs) {
            System.out.println("s1:" + JSON.toJSONString(s1));
            for (String s2 : s1) {
                //  System.out.println("s2:"+s2);
            }
        }

        List<String> distinctStrs2 = Arrays.stream(strs)
                .map(str -> str.split(""))  // 映射成为Stream<String[]>
                .flatMap(Arrays::stream)  // 扁平化为Stream<String>
                        //.distinct()
                .collect(Collectors.toList());
        System.out.println(distinctStrs2);
    }

    //list的内容的不变,filter只有true才会显示出来的。
    public static void streamFilter(List<Integer> list) {
        List f = list.stream().filter(e -> e == 1).collect(Collectors.toList());
        System.out.println("a1:" + JsonUtil.toJson(list));
        System.out.println(f);
    }

    //list to map

    public static void listToMap() {
        //方法一，缺点：IllegalStateException: Duplicate key 土木工程，必须让key不重复
//       Map<String,String> studentMapStringToString =   students.stream().collect(Collectors.toMap(Student::getName, Student::getMajor));
//        System.out.println("a1:"+ JsonUtil.toJson(studentMapStringToString));

        //解决Key重复的，后者覆盖前者的

        Map<String, String> studentMapStringToString2 = students.stream().collect(Collectors.toMap(Student::getName, Student::getMajor, (key1, key2) -> key2));

        System.out.println("a1:" + JsonUtil.toJson(studentMapStringToString2));

    }

    //获取Id映射StudentMap
    public Map<Long, Student> getIdStudentMap(List<Student> accounts) {
        return accounts.stream().collect(Collectors.toMap(Student::getId, Function.identity(),(key1,key2)->key2));
    }

    public Map<Long, Student> getNameAccountMap(List<Student> accounts) {
        return accounts.stream().collect(Collectors.toMap(Student::getId, Function.identity(), (key1, key2) -> key2, LinkedHashMap::new));
    }
    }